/*
 * wrapcaps.cxx
 *
 * OpenH323 Wrapper Library.
 *
 * Copyright (c) 2002-2005 InAccess Networks
 * Michalis Manousos <manousos@inaccessnetworks.com>
 * Dimitris Economou <decon@inaccessnetworks.com>
 *
 * This file is part of "H.323 support for ASTERISK"
 *
 * "H.323 support for ASTERISK" is free software;
 * you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation;
 * either version 2 of the License, or (at your option) any later version. 
 *
 * "H.323 support for ASTERISK" is distributed in the hope that it will be 
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. 
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 * $Id: wrapcaps.cxx,v 1.1.1.1 2007/06/04 10:55:30 mmanousos Exp $
 *
 */

/************************************************************************/

#include <ptlib.h>
#include <h323.h>
#include <h323pdu.h>

#define cplusplus
#include "version.h"
#include "wrapcaps.hxx"
#include "wrapper_misc.hxx"

using namespace std;

#ifdef	USE_OLD_CAPABILITIES_API

//////////////////////////////////////////////////////////////////////////

OpalMediaFormat const WrapG726_40(WRAP_G726_40,
						OpalMediaFormat::DefaultAudioSessionID,
						RTP_DataFrame::G726,
						TRUE,		// Needs jitter
						40000,		// bits/sec
						5,			// 5 bytes per "frame"
						8,			// 1 millisecond per "frame"
						OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const WrapG726_32(WRAP_G726_32,
						OpalMediaFormat::DefaultAudioSessionID,
						RTP_DataFrame::G726,
						TRUE,		// Needs jitter
						32000,		// bits/sec
						4,			// 4 bytes per "frame"
						8,			// 1 millisecond per "frame"
						OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const WrapG726_24(WRAP_G726_24,
						OpalMediaFormat::DefaultAudioSessionID,
						RTP_DataFrame::G726,
						TRUE,		// Needs jitter
						24000,		// bits/sec
						3,			// 3 bytes per "frame"
						8,			// 1 millisecond per "frame"
						OpalMediaFormat::AudioTimeUnits);

OpalMediaFormat const WrapG726_16(WRAP_G726_16,
						OpalMediaFormat::DefaultAudioSessionID,
						RTP_DataFrame::G726,
						TRUE,		// Needs jitter
						16000,		// bits/sec
						2,			// 2 bytes per "frame"
						8,			// 1 millisecond per "frame"
						OpalMediaFormat::AudioTimeUnits);

H323_REGISTER_CAPABILITY_FUNCTION(G72640Capability, WRAP_G726_40"{hw}", ep)
{
	return new Wrap_G726_Capability(ep, WRAP_G726_SPEED40);
}
H323_REGISTER_CAPABILITY_FUNCTION(G72632Capability, WRAP_G726_32"{hw}", ep)
{
	return new Wrap_G726_Capability(ep, WRAP_G726_SPEED32);
}
H323_REGISTER_CAPABILITY_FUNCTION(G72624Capability, WRAP_G726_24"{hw}", ep)
{
	return new Wrap_G726_Capability(ep, WRAP_G726_SPEED24);
}
H323_REGISTER_CAPABILITY_FUNCTION(G72616Capability, WRAP_G726_16"{hw}", ep)
{
	return new Wrap_G726_Capability(ep, WRAP_G726_SPEED16);
}

#else

//////////////////////////////////////////////////////////////////////////

char WrapG726_40[] = WRAP_G726_40;

OPAL_MEDIA_FORMAT_DECLARE(WrapG726_40_Format, 
				WrapG726_40,
				OpalMediaFormat::DefaultAudioSessionID,
				RTP_DataFrame::G726,
				TRUE,		// Needs jitter
				40000,		// bits/sec
				5,			// 5 bytes per "frame"
				8,			// 1 millisecond per "frame"
				OpalMediaFormat::AudioTimeUnits,
				0)

//////////////////////////////////////////////////////////////////////////

char WrapG726_32[] = WRAP_G726_32;

OPAL_MEDIA_FORMAT_DECLARE(WrapG726_32_Format, 
				WrapG726_32,
				OpalMediaFormat::DefaultAudioSessionID,
				RTP_DataFrame::G726,
				TRUE,		// Needs jitter
				32000,		// bits/sec
				4,			// 4 bytes per "frame"
				8,			// 1 millisecond per "frame"
				OpalMediaFormat::AudioTimeUnits,
				0)

//////////////////////////////////////////////////////////////////////////

char WrapG726_24[] = WRAP_G726_24;

OPAL_MEDIA_FORMAT_DECLARE(WrapG726_24_Format, 
				WrapG726_24,
				OpalMediaFormat::DefaultAudioSessionID,
				RTP_DataFrame::G726,
				TRUE,		// Needs jitter
				24000,		// bits/sec
				3,			// 3 bytes per "frame"
				8,			// 1 millisecond per "frame"
				OpalMediaFormat::AudioTimeUnits,
				0)

//////////////////////////////////////////////////////////////////////////

char WrapG726_16[] = WRAP_G726_16;

OPAL_MEDIA_FORMAT_DECLARE(WrapG726_16_Format, 
				WrapG726_16,
				OpalMediaFormat::DefaultAudioSessionID,
				RTP_DataFrame::G726,
				TRUE,		// Needs jitter
				16000,		// bits/sec
				2,			// 2 bytes per "frame"
				8,			// 1 millisecond per "frame"
				OpalMediaFormat::AudioTimeUnits,
				0)

//////////////////////////////////////////////////////////////////////////

H323EndPoint *dummy_ep = NULL;

#define DEFINE_G726LID_CAPABILITY(cls, capName, speed) \
class cls : public Wrap_G726_Capability { \
  public: \
    cls() : Wrap_G726_Capability(*dummy_ep, speed) { } \
}; \
H323_REGISTER_CAPABILITY(cls, capName) \

DEFINE_G726LID_CAPABILITY(G72640Capability, WRAP_G726_40"{hw}", WRAP_G726_SPEED40)
DEFINE_G726LID_CAPABILITY(G72632Capability, WRAP_G726_32"{hw}", WRAP_G726_SPEED32)
DEFINE_G726LID_CAPABILITY(G72624Capability, WRAP_G726_24"{hw}", WRAP_G726_SPEED24)
DEFINE_G726LID_CAPABILITY(G72616Capability, WRAP_G726_16"{hw}", WRAP_G726_SPEED16)

#endif

// G.726 Non-statndard info
struct Wrap_G726_nsInfo {
	char name[10];
	BYTE count;
};
static Wrap_G726_nsInfo const Wrap_G726_Info[4] = {
	{ WRAP_G726_40, 5 },
	{ WRAP_G726_32, 4 },
	{ WRAP_G726_24, 3 },
	{ WRAP_G726_16, 2 }
};

//////////////////////////////////////////////////////////////////////////

Wrap_G726_Capability::Wrap_G726_Capability(H323EndPoint &ep, int sp)
#ifdef USE_OLD_CAPABILITIES_API
	: H323NonStandardAudioCapability(240, 10, ep, 
			(const BYTE*)&(Wrap_G726_Info[sp]), // non-standard data for codec
			sizeof(Wrap_G726_Info),             // size of datablock
			0,                              // offset into datablock to compare
			sizeof(Wrap_G726_Info[sp].name) // length of bytes to compare
		)
#else
	: H323NonStandardAudioCapability(240, 10,
			(const BYTE*)&(Wrap_G726_Info[sp]), // non-standard data for codec
			sizeof(Wrap_G726_Info),             // size of datablock
			0,                              // offset into datablock to compare
			sizeof(Wrap_G726_Info[sp].name) // length of bytes to compare
		)
#endif
{
	speed = sp;
	WRAPTRACE(4, "Created capability " << PString(Wrap_G726_Info[sp].name));
}

PObject * Wrap_G726_Capability::Clone() const
{
	return new Wrap_G726_Capability(*this);
}

PString Wrap_G726_Capability::GetFormatName() const
{
	return PString(Wrap_G726_Info[speed].name) + "{hw}";
}

BOOL Wrap_G726_Capability::OnSendingPDU(H245_AudioCapability & pdu,
										unsigned packetSize) const
{
	Wrap_G726_nsInfo *info = (Wrap_G726_nsInfo *)(const BYTE *)nonStandardData;
	info->count = (BYTE)packetSize;
	return H323NonStandardAudioCapability::OnSendingPDU(pdu, packetSize);
}

BOOL Wrap_G726_Capability::OnReceivedPDU(const H245_AudioCapability & pdu,
										unsigned & packetSize)
{
	if (!H323NonStandardAudioCapability::OnReceivedPDU(pdu, packetSize))
		return FALSE;

	const Wrap_G726_nsInfo *info = (Wrap_G726_nsInfo *)(const BYTE *)nonStandardData;
	packetSize = info->count;
	return TRUE;
}

BOOL Wrap_G726_Capability::IsValid() const
{
	return TRUE;
}

H323Codec *Wrap_G726_Capability::CreateCodec(H323Codec::Direction direction) const
{
	unsigned frameNum = (direction == H323Codec::Encoder ? 
										txFramesInPacket : rxFramesInPacket);
	return new Wrap_G726_Codec(speed, direction, frameNum);
}

Wrap_G726_Codec::Wrap_G726_Codec(int sp, Direction dir, unsigned frameNum)
	: H323AudioCodec(Wrap_G726_Info[sp].name, dir)
{
	// 1 frame G.726 represents 1 ms voice (same assumption as in G.711)
	// This voice period contains 8 samples G.726
	speed = sp;
	packetSize = (5 - speed) * frameNum;
	samplesPerFrame = 8 * frameNum;
	WRAPTRACE(3, "Created codec: pt=" << PString(Wrap_G726_Info[sp].name)
			<< ", bytes=" << packetSize << ", samples=" << samplesPerFrame);
}

// Returns the G.726 speed in bytes per ms
unsigned Wrap_G726_Codec::GetSpeed()
{
	return (5 - speed);
}

BOOL Wrap_G726_Codec::Read(BYTE *buffer, unsigned &length, RTP_DataFrame &)
{
	PINDEX count;
	PWaitAndSignal mutex(rawChannelMutex);
	if (!ReadRaw(buffer, packetSize, count))
		return FALSE;
	length = count;
	return TRUE;
}

BOOL Wrap_G726_Codec::Write(const BYTE * buffer,
							unsigned length,
							const RTP_DataFrame & /*frame*/,
							unsigned & written)
{
	//BYTE silenceBuffer[1024] = {0};

	if (length > packetSize)
		length = packetSize;
#if 0
	if (length == 0) {
		// XXX Fix this!
		buffer = (BYTE *)silenceBuffer;
		length = packetSize;
	}
#endif
	PWaitAndSignal mutex(rawChannelMutex);
	if (!rawDataChannel->Write(buffer, length))
		return FALSE;
	written = rawDataChannel->GetLastWriteCount();
	return TRUE;
}
 
BOOL Wrap_G726_Codec::IsRawDataChannelNative() const
{
	return TRUE;
}

